package com.leyou.search.service.impl;

import com.leyou.common.dto.PageDTO;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpecParamDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.search.service.IndexService;

import com.leyou.search.entity.Goods;
import com.leyou.search.repostitory.GoodsRepository;
import com.sun.javafx.collections.SetListenerHelper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class IndexServiceImpl implements IndexService {


    @Autowired
    private ItemClient itemClient;

    @Autowired
    private GoodsRepository goodsRepository;



    //1.先连接es, 创建goods索引库 ,是spu的综合
    //需要访问
    @Override
    public void loadData() { // todo 批量导入数据

        // TODO: 2020/12/12 先删除索引库，在添加索引库
        deleteAndCreateIndex();


        int page = 1;

        while (true) { //获取分页数据   跨服务查询
            PageDTO<SpuDTO> spuDTOPageDTO = this.itemClient.pageQuery(page, 50, null, null, null, true);

            //根本没有数据 直接结束
            if (0==spuDTOPageDTO.getTotalPage()){
                break;
            }

            //把获得的spuDTO转化为 goodsList
       /*     List<Goods> goods1 = new ArrayList<>();
            List<SpuDTO> items = spuDTOPageDTO.getItems();
            for (SpuDTO item : items) {
                Goods goods = buildGoods(item);
                goods1.add(goods);//todo 此五行等同于下面一行
            }*/

           //拿到了一部分属性的 goods 内容
            List<Goods> goodsList = spuDTOPageDTO.getItems().stream().map(this::buildGoods).collect(Collectors.toList());
            //批量保存 goods到索引库
            this.goodsRepository.saveAll(goodsList);


            page++;
            if (page>spuDTOPageDTO.getTotalPage()){//如果当前页码大于总页码,结束死循环;
                break;
            }


        }
    }

    private void deleteAndCreateIndex() {
        //todo 先删除索引库 在创建索引库
        try { //先进行删除索引库,如果原本就没有索引库,异常被捕捉,继续往下执行
            this.goodsRepository.deleteIndex();
        } catch (Exception e) {
        }
        // TODO: 2020/12/12 创建索引库
        this.goodsRepository.createIndex("{\n" +
                "  \"settings\": {\n" +
                "    \"analysis\": {\n" +
                "      \"analyzer\": {\n" +
                "        \"my_pinyin\": {\n" +
                "          \"tokenizer\": \"ik_smart\",\n" +
                "          \"filter\": [\n" +
                "            \"py\"\n" +
                "          ]\n" +
                "        }\n" +
                "      },\n" +
                "      \"filter\": {\n" +
                "        \"py\": {\n" +
                "\t\t  \"type\": \"pinyin\",\n" +
                "          \"keep_full_pinyin\": true,\n" +
                "          \"keep_joined_full_pinyin\": true,\n" +
                "          \"keep_original\": true,\n" +
                "          \"limit_first_letter_length\": 16,\n" +
                "          \"remove_duplicated_term\": true\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  },\n" +
                "  \"mappings\": {\n" +
                "    \"properties\": {\n" +
                "      \"id\": {\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"suggestion\": {\n" +
                "        \"type\": \"completion\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"title\":{\n" +
                "        \"type\": \"text\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"image\":{\n" +
                "        \"type\": \"keyword\",\n" +
                "        \"index\": false\n" +
                "      },\n" +
                "      \"updateTime\":{\n" +
                "        \"type\": \"date\"\n" +
                "      },\n" +
                "      \"specs\":{\n" +
                "        \"type\": \"nested\",\n" +
                "        \"properties\": {\n" +
                "          \"name\":{\"type\": \"keyword\" },\n" +
                "          \"value\":{\"type\": \"keyword\" }\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  }\n" +
                "}");
    }

    //todo 把查询到的spuDto 转化为Goods 并最终存到索引库中
    @Override
    public Goods buildGoods(SpuDTO spuDTO){

        Goods goods = new Goods();

        BeanUtils.copyProperties(spuDTO,goods);



        //categoryId
        goods.setCategoryId(spuDTO.getCid3());
        //updateTime
        goods.setUpdateTime(new Date());


        //todo suggestion  //候选值，主体名称，品牌+主体，品牌+分类，分类+品牌
        //索引库中的 suggestion 就是在搜索栏中 输入首字母 主动补全的内容
        ArrayList<String> suggestion = new ArrayList<>();
        //String categoryName= spuDTO.getCategoryName().split("/")[2]; //分类名字
        String goodsName = spuDTO.getName();// 商品主体名称
        String categoryName = StringUtils.substringAfterLast(spuDTO.getCategoryName(), "/");//分类名称
        String brandName = StringUtils.substringBefore(spuDTO.getBrandName(),"（");//品牌名字

        suggestion.add(goodsName);
        suggestion.add(goodsName.startsWith(brandName) ? brandName:brandName+goodsName);//主体如果以品牌名开头，就放品牌名
        suggestion.add(brandName+categoryName);
        suggestion.add(categoryName+brandName);
        goods.setSuggestion(suggestion);

        String title =goodsName+" "+brandName+" "+categoryName;
        goods.setTitle(title);


        //todo 以下是sku信息
        //跨服务 获得 skuDTOSd的所有价格
        //todo prices
        List<SkuDTO> skuDTOS = this.itemClient.querySkusBySpuId(spuDTO.getId());

        Set<Long> prices = new HashSet<>();//set集合去重
        long sold=0;//设置销量初始值
        for (SkuDTO skuDTO : skuDTOS) {
            Long price = skuDTO.getPrice();
            prices.add(price);
            sold+=skuDTO.getSold();
        }

        goods.setPrices(prices);
        //sold
        goods.setSold(sold);
        //image 在SpuDetail
        String images = StringUtils.substringBefore(skuDTOS.get(0).getImages(),","); //随便取sku的一张图片，确保只有一张

        goods.setImage(images);

        //specs TODO 可搜索的规格参数,以及它的值

        List<Map<String,Object>> specs = new ArrayList<>();
        //获取所有的可搜索的规格参数
        List<SpecParamDTO> specParamDTOS = this.itemClient.listSpecByspuId(spuDTO.getId(), true);//根据spuid查询对应得规格参数组集合 以及组内参数信息 及对应值
       // 取出参数名称作为may 的key,参数的值value作为map的value

        for (SpecParamDTO specParamDTO : specParamDTOS) {
            Map<String, Object> resultMap = new HashMap<>();//放在循环里面,每次map添加的都是新的value
            resultMap.put("name",specParamDTO.getName());

            //resultMap.put("value",specParamDTO.getValue());
            //value 如果是数值,有区间,选择区间
            resultMap.put("value",chooseSegment(specParamDTO));//todo 方法在下
            specs.add(resultMap);
        }



        goods.setSpecs(specs);

        return goods;
    }

    //todo 创建索引id
    @Override
    public void crateIndex(Long id) {
        //根据spuid做查询
        PageDTO<SpuDTO> spuDTOPageDTO = this.itemClient.pageQuery(1, 1, null, null,id, true);

        //如果查询到了
       if (1==spuDTOPageDTO.getTotal()){//查到1个结果
           SpuDTO spuDTO = spuDTOPageDTO.getItems().get(0);//获取当前页数据
           //todo 前面封装的方法 buildGoods(spuDTO) 转化为 goods 并且保存
           this.goodsRepository.save(buildGoods(spuDTO));
       }

    }

    // todo 删除索引库中其中一条数据
    @Override
    public void deteleIndex(Long id) {

        this.goodsRepository.deleteById(id);
    }


    private Object chooseSegment(SpecParamDTO p) {
        Object value = p.getValue();
        if (value == null || StringUtils.isBlank(value.toString())) {
            return "其它";
        }
        if (!p.getNumeric() || StringUtils.isBlank(p.getSegments()) || value instanceof Collection) {
            return value;
        }
        double val = parseDouble(value.toString());
        String result = "其它";
        // 保存数值段
        for (String segment : p.getSegments().split(",")) {
            String[] segs = segment.split("-");
            // 获取数值范围
            double begin = parseDouble(segs[0]);
            double end = Double.MAX_VALUE;
            if (segs.length == 2) {
                end = parseDouble(segs[1]);
            }
            // 判断是否在范围内
            if (val >= begin && val < end) {
                if (segs.length == 1) {
                    result = segs[0] + p.getUnit() + "以上";
                } else if (begin == 0) {
                    result = segs[1] + p.getUnit() + "以下";
                } else {
                    result = segment + p.getUnit();
                }
                break;
            }
        }
        return result;
    }

    private double parseDouble(String str) {
        try {
            return Double.parseDouble(str);
        } catch (Exception e) {
            return 0;
        }
    }




}
